#ifndef _Ring_QUEUE_HPP_
#define _Ring_QUEUE_HPP_

#include <iostream>
#include <vector>
#include <pthread.h>
#include "sem.hpp"

const int g_default_num = 5;

template <class T>
class RingQueue
{
public:
    RingQueue(int n = g_default_num)
        : _num(n), _ring_queue(n), c_step(0), p_step(0), space_sem(n), data_sem(0)
    {
        pthread_mutex_init(&clock, NULL);
        pthread_mutex_init(&plock, NULL);
    }

    ~RingQueue()
    {
        pthread_mutex_destroy(&clock);
        pthread_mutex_destroy(&plock);
    }

    void push(const T &in)
    {
        space_sem.p();
        pthread_mutex_lock(&plock);
        _ring_queue[p_step++] = in;
        p_step %= _num;
        pthread_mutex_unlock(&plock);
        data_sem.v();
    }

    void pop(T *out)
    {
        data_sem.p();
        *out = _ring_queue[c_step++];
        c_step %= _num;
        space_sem.v();
    }

private:
    std::vector<T> _ring_queue;
    int _num;
    int c_step, p_step;
    Sem space_sem, data_sem;
    pthread_mutex_t clock, plock;
};
#endif